package com.idanchuang.component.just.web.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.idanchuang.component.core.Dc;
import com.idanchuang.component.core.ServiceInfo;
import com.idanchuang.component.core.helper.EnvContext;
import com.idanchuang.component.core.util.PtsUtil;
import com.idanchuang.component.logback.helper.LogContext;
import com.zoi7.component.core.base.BaseClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;
import java.util.Map;

/**
 * 第一个内置过滤器
 * @author yjy
 */
public class FirstFilter extends BaseClass implements InnerWebFilter {

    private static final Logger logger = LoggerFactory.getLogger(FirstFilter.class);

    @Override
    public boolean matchUrlPatterns(ServletRequest req) {
        return true;
    }

    @Override
    public boolean preFilter(ServletRequest req, ServletResponse res) {
        // 请求头收集
        collectRequestHeader(req);
        // 响应头设置
        addResponseHeader(res);
        return true;
    }

    @Override
    public void postFilter(ServletRequest req, ServletResponse res) {
        // 清除attributes
        EnvContext.clearContext();
    }

    /**
     * 收集header信息, 并存入当前上下文
     * @param req ..
     */
    private void collectRequestHeader(ServletRequest req) {
        HttpServletRequest request = (HttpServletRequest) req;
        try {
            // 清理当前残留的变量
            EnvContext.clearContext();

            // 将当前Path记录ThreadLocal
            EnvContext.setCurrentPath(request.getRequestURI());

            // 取出流量标, 保存流量标
            String headerValue = request.getHeader(EnvContext.getEnvHeaderName());
            if (headerValue != null) {
                EnvContext.setCurrentEnv(headerValue);
            }
            // 取出前端traceId, 没有则生成一个
            String dcTraceId = request.getHeader(EnvContext.getDcTraceIdHeaderName());
            if (dcTraceId == null) {
                dcTraceId = EnvContext.createDcTraceId();
            }
            EnvContext.setDcTraceIdIfAbsent(dcTraceId);
            // 取出时光机偏移量, 保存至上下文
            String tmo = request.getHeader(Dc.TIME_MACHINE_OFFSET_HEADER);
            if (tmo != null && !tmo.isEmpty()) {
                EnvContext.setAttribute(Dc.TIME_MACHINE_OFFSET, tmo);
            }
            // 取出用户信息存入上下文
            String userId = request.getHeader(Dc.USER_ID_HEADER);
            if (userId != null) {
                EnvContext.setAttribute(Dc.USER_ID, userId);
            }
            String userIdCode = request.getHeader(Dc.USER_ID_CODE_HEADER);
            if (userIdCode != null) {
                EnvContext.setAttribute(Dc.USER_ID_CODE, userIdCode);
            }
            // 请求诊断
            String diag = request.getHeader(Dc.DIAG_HEADER);
            if (notBlank(diag)) {
                EnvContext.setAttribute(Dc.DIAG, diag);
            }
            // 特定服务实例
            String ptsSi = request.getHeader(Dc.SPECIAL_INSTANCE_HEADER);
            Map<String, String> siMap = PtsUtil.parsePtsSi(ptsSi);
            if (siMap != null) {
                EnvContext.setAttribute(Dc.SPECIAL_INSTANCE, siMap);
            }
            // 环境变量
            String attributes = request.getHeader(EnvContext.TRANSMIT_ATTRIBUTE_HEADER_NAME);
            if (notBlank(attributes)) {
                attributes = URLDecoder.decode(attributes, "UTF-8");
                EnvContext.setAllAttribute(JSON.parseObject(attributes));
            }
            // 记录入口请求信息
            if (!EnvContext.existAttribute(Dc.ORIGIN_REQUEST)) {
                String originReq = ServiceInfo.getAppId().toLowerCase() + ":" + request.getServletPath();
                EnvContext.setAttribute(Dc.ORIGIN_REQUEST, originReq);
            }
        } catch (Exception e) {
            // 降级
            LogContext.setKeyword("componentError");
            logger.error("Collect Request Header error", e);
        }
    }

    /**
     * 扩展响应头
     * @param response ..
     */
    private void addResponseHeader(ServletResponse response) {
        try {
            // 响应头带上 环境信息 / 链路id
            if (response instanceof HttpServletResponse) {
                HttpServletResponse httpServletResponse = ((HttpServletResponse) response);
                String currentEnv = EnvContext.getCurrentEnv();
                if (currentEnv != null) {
                    httpServletResponse.addHeader(EnvContext.getEnvHeaderName(), currentEnv);
                }
                String dcTraceId = EnvContext.getDcTraceId();
                if (dcTraceId != null) {
                    httpServletResponse.addHeader(EnvContext.getDcTraceIdHeaderName(), dcTraceId);
                }
            }
        } catch (Exception e) {
            // 降级
            LogContext.setKeyword("componentError");
            logger.error("Add Response Header error", e);
        }
    }

}
